package com.hs.egova.tool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSetMetaData;

import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

/**
 * 结果集行映射工具类
 * 暂时只支持mysql
 * @author husheng
 * @version v1.0
 * @date 2021/7/26 14:31
 * @email husheng@egova.com.cn
 */
@Slf4j
public class ObjRowMapper<T> implements RowMapper<T> {

    private Class<T> rowClass;
    private Map<String, Method> methodMap = new HashMap<>();

    public ObjRowMapper(Class<T> rowClass) {
        super();
        this.rowClass = rowClass;
        for (Method method : this.rowClass.getMethods()) {
            if (method.getName().startsWith("set") && method.getParameters().length == 1) {
                methodMap.put(method.getName().toUpperCase(), method);
            }
        }
    }

    @Override
    public T mapRow(ResultSet resultSet, int i) throws SQLException {

        T object = null;
        //获取列数据
        ResultSetWrappingSqlRowSetMetaData wapping = new ResultSetWrappingSqlRowSetMetaData(resultSet.getMetaData());
        int columnCount = wapping.getColumnCount();
        int columnIndex = 0;
        for(; columnIndex++ != columnCount; ) {
            String columnClassName = wapping.getColumnClassName(columnIndex);
            Object value = resultSet.getObject(columnIndex);
            //对于空值，如果不是字符串直接处理下一个字段
            if (value == null && !"java.lang.String".equals(columnClassName)) {
                continue;
            }
            //一般在读取首列数据创建对象
            if (columnIndex == 1 || object == null) {
                try {
                    object = this.rowClass.newInstance();
                } catch (Exception e) {
                    log.error("未能初始化类的实例，请检查构造函数或者权限！{}", e);
                }
            }
            //找的和当前字段名称一致的对象属性设置方法，然后赋值，去掉数据库表字段的下划线java使用大小区别，数据库字段没有大小写，只能使用下划线
            //getColumnName返回的是SQL语句原始名字，getColumnLabel是field的SQL AS的值
            String columnName = wapping.getColumnLabel(columnIndex).replaceAll("_", "");
            int type = wapping.getColumnType(columnIndex);

            Method method = methodMap.get("set".concat(columnName).toUpperCase());
            if (method == null) {
                continue;
            }

            String paramterType = method.getParameters()[0].getName();
            //获取列值
            switch (type) {
                case Types
                        .BIGINT :
                    value = resultSet.getLong(columnIndex);
                break;
                case Types.CHAR:
                case Types.LONGNVARCHAR:
                case Types.VARCHAR:
                    value = (value == null) ? "" : resultSet.getString(columnIndex);
                    break;
                case Types.TINYINT:
                case Types.INTEGER:
                    value = resultSet.getInt(columnIndex);
                    break;
                case Types.DOUBLE:
                    value = resultSet.getDouble(columnIndex);
                    break;
                case Types.DECIMAL:
                    value = resultSet.getBigDecimal(columnIndex);
                    try {
                        if("int".equals(paramterType)) {
                            value = resultSet.getBigDecimal(columnIndex).intValue();
                        }
                    }catch (Exception e) {

                    }
                    break;
                case Types.REAL:
                    value = resultSet.getFloat(columnIndex);
                    break;
                case Types.BIT:
                    value = resultSet.getBoolean(columnIndex);
                    break;
                case Types.DATE:
                    value = resultSet.getDate(columnIndex);
                    break;
                case Types.TIME:
                    value = resultSet.getTime(columnIndex);
                    break;
                case Types.TIMESTAMP:
                    value = resultSet.getTimestamp(columnIndex);
                    break;
                case Types.NUMERIC:
                    if ("int".equals(paramterType) || "java.lang.Integer".equals(paramterType)) {
                        value = resultSet.getInt(columnIndex);
                    } else if ("long".equals(paramterType) || "java.lang.Long".equals(paramterType)) {
                        value = resultSet.getLong(columnIndex);
                    } else if ("float".equals(paramterType) || "java.lang.Float".equals(paramterType)) {
                        value = resultSet.getFloat(columnIndex);
                    } else if ("double".equals(paramterType) || "java.lang.Double".equals(paramterType)) {
                        value = resultSet.getDouble(columnIndex);
                    } else if ("boolean".equals(paramterType) || "java.lang.Boolean".equals(paramterType)) {
                        value = resultSet.getBoolean(columnIndex);
                    }
                    break;
                default:
                    break;
            }

            //执行setter
            try {
                method.invoke(object, value);
            }catch (Exception e) {

            }
            return object;
        }
        return null;
    }
}
